use crate::{
    parser::Value,
    runtime::{Env, FuncBinds},
};

use super::Builtin;

pub fn bind(env: &mut FuncBinds) {
    env.bind_builtin("type", Type);
    env.bind_builtin("isDefined", IsDefined);
}

struct IsDefined;

impl Builtin for IsDefined {
    fn call(&self, env: &Env, argv: &[Value]) -> Result<Value, ()> {
        let [Value::Symbol(name)] = argv else {
            return Err(());
        };
        Ok(Value::Bool(env.find(name).is_some()))
    }
}

struct Type;

impl Builtin for Type {
    fn call(&self, _: &Env, argv: &[Value]) -> Result<Value, ()> {
        let [v] = argv else {
            return Err(());
        };

        let name = match v {
            Value::Bool(_) => "Bool",
            Value::Symbol(_) => "Symbol",
            Value::Path(_) => "Path",
            Value::OsString(_) => "OsString",
            Value::String(_) => "String",
            Value::Integer(_) => "Integer",
            Value::Array(_) => "Array",
            Value::Hash(_) => "Hash",
        };

        Ok(Value::String(name.to_string()))
    }
}
